package model.webService;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.SocketException;

import org.json.JSONException;

import view.ArgusActivity;
import view.Scanner;
import model.OnScreen;
//import model.webService.ClientThread.ViewTransition;



import model.webService.translation.JSONBehaviour;
import model.webService.translation.ServiceBehaviour;

import com.vandorenmes.argusv6_5.R;

import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

/**
 * Handles incoming calls from webservice.
 */
public class CallReceiver
{
	private final String TAG = CallReceiver.class.getSimpleName();
	
	private ArgusActivity _activity = null;
	private Socket webServerSocket = null;
	
	private Command lastCommand = Command.Login;
	
	public CallReceiver(Socket webServerSocket, ArgusActivity activity)
	{
		_activity = activity;
		this.webServerSocket = webServerSocket;
	}

	/**
	 * Start listening for messages from the webservice.
	 */
	public void listen()
	{
		if(webServerSocket != null)
		{					
			// keep listening		
	    	while(webServerSocket.isConnected() && !webServerSocket.isClosed())
	    	{
	    		BufferedReader in;
				try 
				{
					in = new BufferedReader(new InputStreamReader(webServerSocket.getInputStream()));
					
					readResponse(in);
				} catch (IOException e) {
					Log.e(TAG, e.toString());
				}
	    	}
		}
		
		handleLostConnection();
	}

	/**
	 * read an incoming message from the server
	 */
	private void readResponse(BufferedReader in) 
	{
		try
		{
			String response = "";
			while((response = in.readLine()) != null)
			{
				Log.i(TAG, response);
				handleReceivedMessage(response);
			}
		} catch (SocketException e)
		{
			Log.e(TAG, e.toString());
			handleLostConnection();
		}catch(Exception e)
		{
			Log.e(TAG, "read: " + e.toString());
		}
	}

	/**
	 * Handles incoming message.
	 * <p>Incoming messages should not be empty<p>
	 * @param message The message received.
	 */
	private void handleReceivedMessage(String message) throws Exception
	{
		if(message.trim().isEmpty())
			throw new Exception(String.format("cmd: \'%s\' returned empty message", lastCommand.toString()));
		
		switch(lastCommand)
    	{
			case Login:
				logIn();
				break;
			case Logout:
				logOut();
				break;
			case AllSnippets:
			case getSnippet:
			case Subscribe:
			case ReceiveUpdate:
			default:
				Log.i(TAG, lastCommand.toString());
				translateSnippets(message);
				break;
    	}		
	}
	
	/**
	 * Sends a call to the webservice with an attempt to connect.
	 */
	private void logIn() throws SocketException
	{
		if(OnScreen.getInstance().getSnippets().isEmpty())
		{
			CallSender.sendSocketCall(webServerSocket, Command.AllSnippets);
			setLastCommand(Command.AllSnippets);
		}
	}
	
	/**
	 * Sends a call to the webservice with an attempt to disconnect.
	 */
	public void logOut() throws SocketException 
	{
		CallSender.sendSocketCall(webServerSocket, Command.Logout);
		
		webServerSocket = null;
	}

	/**
	 * Attempts to translate the received message into snippet objects.
	 * <p>If the application is currently inside a splash screen, it will change activities.</p>
	 * @param message A string representation of an array of snippets. (JSON)
	 */
	private void translateSnippets(String message) 
	{
		Log.d(TAG, "Translate()");
		
		ServiceBehaviour translator = createTranslator(message);
		try 
		{
			translator.translateResponse(message);
			if(lastCommand == Command.AllSnippets)
				exitSplashScreen();
			lastCommand = Command.ReceiveUpdate;
		} catch (JSONException e) 
		{
			Log.e(TAG, "Invalid JSON");
					_activity.makeToast(R.string.invalid_data);
		} catch (Exception e) 
		{
			Log.e(TAG, e.toString());
		} 
	}

	/**
	 * Exit the splash screen
	 */
	private void exitSplashScreen() 
	{
		Handler handler = new Handler(Looper.getMainLooper());
		handler.post(new ViewTransition());			
	}
	
	/**
	 * Helper class to allow the changing of activities.
	 */
	private class ViewTransition implements Runnable
	{
		@Override
		public void run() 
		{
			Intent intent = new Intent(_activity, Scanner.class);
			_activity.startActivity(intent);
			_activity = null;
		}
	}

	/**
	 * Create a translator suitable for given message.
	 * @param message The message to be translated.
	 * @return The ServiceBehaviour capable of translating the message.
	 * <p><b><i>Currently only JSON available</b></i></p>
	 */
	private ServiceBehaviour createTranslator(String message) 
	{
		return new JSONBehaviour();
	}

	/**
	 * Handles the case of a lost connection.
	 */
	public void handleLostConnection() 
	{
		Log.e(TAG, "Connection lost");
		_activity.makeToast(R.string.connection_lost);
	}
	
	public void setLastCommand(Command command)
	{
		lastCommand = command;
	}

	public void setActivity(ArgusActivity activity) 
	{
		_activity = activity;		
	}
}
